package com.razorthink.shell.utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import com.razorthink.deployment.fabric.core.Command;
import com.razorthink.deployment.fabric.core.FabricSourceBuilder;
import com.razorthink.deployment.fabric.core.Module;
import com.razorthink.shell.core.AbstractCommand;
import com.razorthink.shell.core.entities.Config;
import com.razorthink.shell.core.entities.ServerConfig;

public class Precheck {
	public static final String ENV_VAR_CONFIG = "config";
	public static final String ENV_VAR_SERVERS = "servers";

	/**
	 * Check if the config is loaded into the shell context
	 * 
	 * @param cmd
	 * @return
	 */
	public static boolean isConfigLoaded(AbstractCommand cmd) {
		if (cmd.getEnvVar(ENV_VAR_CONFIG) != null) {
			return true;
		}
		return false;
	}

	/**
	 * Get the loaded config from the shell context
	 * 
	 * @param cmd
	 * @return Config object if config is already loaded.<br/>
	 *         <b>null</b> otherwise.
	 */
	public static Config getLoadedConfig(AbstractCommand cmd) {
		if (isConfigLoaded(cmd)) {
			return (Config) cmd.getEnvVar(ENV_VAR_CONFIG).getValue();
		} else {
			return null;
		}
	}

	/**
	 * Check if the command has any params
	 * 
	 * @param cmd
	 * @return
	 */
	public static boolean hasParams(AbstractCommand cmd) {
		return (cmd.getCommandParser().getParamCount() > 0 ? true : false);
	}

	/**
	 * 
	 * @param cmd
	 * @param cfgFilePath
	 * @return Config object if file is properly parsed<br/>
	 *         <b>null</b> otherwise.
	 */
	public static Config parseConfigFile(AbstractCommand cmd, String cfgFilePath) {
		PropFile p = new PropFile(cfgFilePath);
		CommandLogger.logInfo("Reading config file: " + cfgFilePath);
		try {
			Config c = new Config();
			c.setPROJECT_NAME(p.getProperty("PROJECT_NAME"));
			c.setREMOTE_HOST_ADDRESS(p.getProperty("REMOTE_HOST_ADDRESS"));
			c.setREMOTE_USERNAME(p.getProperty("REMOTE_USERNAME"));
			c.setREMOTE_PASSWORD(p.getProperty("REMOTE_PASSWORD"));
			c.setREMOTE_PATH_TARGET(p.getProperty("REMOTE_PATH_TARGET"));
			c.setREMOTE_PATH_TMP(p.getProperty("REMOTE_PATH_TMP"));
			c.setREMOTE_PATH_TOMCAT_HOME(p
					.getProperty("REMOTE_PATH_TOMCAT_HOME"));
			c.setREMOTE_PATH_LOGS(p.getProperty("REMOTE_PATH_LOGS"));
			c.setREMOTE_MYSQL_PASSWORD(p.getProperty("REMOTE_MYSQL_PASSWORD"));
			c.setREMOTE_MYSQL_USERNAME(p.getProperty("REMOTE_MYSQL_USERNAME"));
			c.setPEM_KEY_FILE(p.getProperty("PEM_KEY_FILE"));
			c.setLOCAL_PATH_PROJECT(p.getProperty("LOCAL_PATH_PROJECT"));
			c.setLOCAL_PATH_DOWNLOAD(p.getProperty("LOCAL_PATH_DOWNLOAD"));
			c.setLOCAL_TMP_WORKING_DIR(p.getProperty("LOCAL_TMP_WORKING_DIR"));
			c.setWARNAME(p.getProperty("WARNAME"));
			c.setSERVER_TYPE(p.getProperty("SERVER_TYPE"));
			c.setSVN_REPO_URL(p.getProperty("SVN_REPO_URL"));
			c.setSVN_USERNAME(p.getProperty("SVN_USERNAME"));
			c.setSVN_PASSWORD(p.getProperty("SVN_PASSWORD"));
			c.setRZT_USER(p.getProperty("RZT_USER"));
			return c;
		} catch (Exception e) {

		}
		return null;
	}

	/**
	 * Set a config object to the env var
	 * 
	 * @param cmd
	 * @param c
	 */
	public static void setConfig(AbstractCommand cmd, Config c) {
		cmd.setEnvVar(ENV_VAR_CONFIG, c);
	}

	/**
	 * Add a new server configuration to the app context.
	 * 
	 * @param cmd
	 * @param serverName
	 * @return
	 */
	public static boolean addServerConfig(AbstractCommand cmd,
			String serverName, Config c) {
		// check if any server config already exists by the same name
		if (getServerConfigList(cmd).size() > 0) {
			for (ServerConfig svr : getServerConfigList(cmd)) {
				if (svr.getName().equals(serverName)) {
					return false;
				}
			}
		}
		// if not, add it to server list in the app context
		ServerConfig newServer = new ServerConfig();
		newServer.setName(serverName);
		newServer.setConfig(c);
		getServerConfigList(cmd).add(newServer);
		return true;
	}

	/**
	 * Get server config by its name from list of loaded servers in app context.
	 * 
	 * @param cmd
	 * @param serverName
	 * @return Server object if found<br/>
	 *         <b>null</b> otherwise.
	 */
	public static ServerConfig getServerConfig(AbstractCommand cmd,
			String serverName) {
		if (getServerConfigList(cmd).size() > 0) {
			for (ServerConfig svr : getServerConfigList(cmd)) {
				if (svr.getName().equals(serverName)) {
					return svr;
				}
			}
		}
		return null;
	}

	/**
	 * Switch from one server config to other in the app context.
	 */
	public static boolean switchServerConfig(AbstractCommand cmd,
			String serverName) {
		if (getServerConfigList(cmd).size() > 0) {
			for (ServerConfig svr : getServerConfigList(cmd)) {
				if (svr.getName().equals(serverName)) {
					setConfig(cmd, svr.getConfig());
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Get configurations of all the servers which have been loaded into app
	 * context.
	 */
	@SuppressWarnings("unchecked")
	public static ArrayList<ServerConfig> getServerConfigList(
			AbstractCommand cmd) {
		if (cmd.getEnvVar(ENV_VAR_SERVERS) == null) {
			cmd.setEnvVar(ENV_VAR_SERVERS, new ArrayList<ServerConfig>());
		}
		return (ArrayList<ServerConfig>) cmd.getEnvVar(ENV_VAR_SERVERS)
				.getValue();
	}

	/**
	 * Create 'sshtemp' directory in remote instance under directory
	 * '/home/user'.
	 * 
	 * @param c
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static void createRemoteSshtempDir(Config c) throws IOException,
			InterruptedException {
		if (doesSshTempDirExist(c)) {
			System.out
					.println("/home/ubuntu/sshtemp directory already exists in the remote instance.");
			return;
		}
		FabricSourceBuilder f = new FabricSourceBuilder();
		f.setUsername(c.getREMOTE_USERNAME());
		f.setPassword(c.getREMOTE_PASSWORD());
		f.setPemKeyfile(c.getPEM_KEY_FILE());
		f.setRemoteHostAddress(c.getREMOTE_HOST_ADDRESS());
		Module createTmpDirModule = new Module("createtempdir");
		createTmpDirModule
				.setRemarks("This module creates sshtemp directory in remote instance");
		createTmpDirModule.addCommand(Command.sudo("mkdir /home/"
				+ c.getREMOTE_USERNAME() + "/sshtemp"));
		createTmpDirModule.addCommand(Command.setFilePermsRecursive(c
				.getREMOTE_PATH_TMP()));
		createTmpDirModule.addCommand(Command.setDirPermsRecursive(c
				.getREMOTE_PATH_TMP()));
		createTmpDirModule.addCommand(Command.sudo("chmod 777 "
				+ c.getREMOTE_PATH_TMP()));
		createTmpDirModule.setContinueWithWarnings(false);
		f.addModule(createTmpDirModule);
		File generated = SourceFileGenerator.getGeneratedFile(
				c.getLOCAL_TMP_WORKING_DIR(),
				createTmpDirModule.getModuleName(), "py");
		f.generatePythonSourceFile(generated);
		String runFabric = "fab -f " + generated.getAbsolutePath()
				+ " -R server " + createTmpDirModule.getModuleName();
		try {
			System.out
					.println("/home/ubuntu/sshtemp directory doesn't exist in the remote instance. Creating it.");
			String response = NativeCommandExecutor.execute(runFabric);
			SourceFileGenerator.deleteGeneratedFiles(generated);
			CommandLogger.logInfo(response);
			System.out.println("/home/ubuntu/sshtemp directory created.");
		} catch (IOException e) {
			CommandLogger.logError(e.getMessage());
		}
	}

	private static boolean doesSshTempDirExist(Config c) throws IOException,
			InterruptedException {
		try {
			FabricSourceBuilder f = new FabricSourceBuilder();
			f.setUsername(c.getREMOTE_USERNAME());
			f.setPassword(c.getREMOTE_PASSWORD());
			f.setPemKeyfile(c.getPEM_KEY_FILE());
			f.setRemoteHostAddress(c.getREMOTE_HOST_ADDRESS());
			Module checkTmpDirModule = new Module("checksshtmp");
			checkTmpDirModule
					.setRemarks("This module checks if sshtemp directory exixts in remote instance");
			checkTmpDirModule.addCommand(Command.sudo("ls -al /home/"
					+ c.getREMOTE_USERNAME() + "/"));
			checkTmpDirModule.setContinueWithWarnings(false);
			f.addModule(checkTmpDirModule);
			File generated = SourceFileGenerator.getGeneratedFile(
					c.getLOCAL_TMP_WORKING_DIR(),
					checkTmpDirModule.getModuleName(), "py");
			f.generatePythonSourceFile(generated);
			String runFabric = "fab -f " + generated.getAbsolutePath()
					+ " -R server " + checkTmpDirModule.getModuleName();

			String response = NativeCommandExecutor.execute(runFabric);
			SourceFileGenerator.deleteGeneratedFiles(generated);
			CommandLogger.logInfo(response);
			if (response.contains("sshtemp")) {
				return true;
			}
		} catch (IOException e) {
			CommandLogger.logError(e.getMessage());
		}
		return false;
	}
}
